package com.xbongbong.saas.model.impl;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormSubDataEntity;
import com.xbongbong.paas.elasticsearch.constant.EsNormalConstant;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.pojo.dto.DeleteDTO;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.EnableApiCallBack;
import com.xbongbong.paas.util.DataUtil;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.ApiCallBackEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.dto.SaasAnalysisDataDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.dao.ClueDao;
import com.xbongbong.saas.domain.entity.ClueSubDataEntity;
import com.xbongbong.saas.domain.entity.FineClueScriptEntity;
import com.xbongbong.saas.domain.entity.RuleClueEntity;
import com.xbongbong.saas.domain.entity.ext.ClueEntityExt;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.help.ShowFormatHelp;
import com.xbongbong.saas.model.ClueModel;
import com.xbongbong.saas.model.ClueSubDataModel;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.saas.util.StandardizeDataUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.ScriptSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author long
 * @version v1.0
 * @date 2020/11/4 10:49
 * @since v1.0
 */
@Service("clueModel")
public class ClueModelImpl implements ClueModel {

    @Resource
    private ClueDao clueDao;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;
    @Resource
    private ClueSubDataModel clueSubDataModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private ShowFormatHelp showFormatHelp;
    @Resource
    private EsHelper esHelper;

    @Override
    public ClueEntityExt getByKey(Long key, String corpid) {
        ClueEntityExt clueEntityExt = clueDao.getByKey(key, corpid);
        paasFormSubDataModel.findSubEntity(corpid, Collections.singletonList(clueEntityExt), IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        return clueEntityExt;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.CLUE, operateTypeEnum = OperateTypeEnum.NEW)
    public Integer insert(ClueEntityExt entity) throws XbbException {
        //TODO  先进行数据库的插入动作
        long now = DateUtil.getInt();
        entity.setAddTime(now);
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        StandardizeDataUtil.standardizeNotString(entity);
        Integer success = clueDao.insert(entity);
        PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
        BeanUtil.copyProperties(entity, paasFormDataEntity);
        InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_CLUE);
        insertDTO.setWaitUntil(WriteRequest.RefreshPolicy.WAIT_UNTIL);
        paasEsModel.insert(insertDTO);

        paasFormSubDataModel.insertSubFormData(entity, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        return success;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.CLUE, operateTypeEnum = OperateTypeEnum.EDIT)
    public Integer update(ClueEntityExt entity) throws XbbException {
        long now = DateUtil.getInt();
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        Integer updateSub = paasFormSubDataModel.updateSubFormData(entity, IndexTypeEnum.IDX_SAAS_CLUE_SUB);

        StandardizeDataUtil.standardizeNotString(entity);
        Integer success = clueDao.update(entity);
        if (Objects.equals(1, success) || Objects.equals(1, updateSub)) {
            // 更新时间
            success = clueDao.updateTime(now + 1, entity.getId(), entity.getCorpid());
            PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
            BeanUtil.copyProperties(entity, paasFormDataEntity, false);
            paasFormDataEntity.setCreatorId(null);
            InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_CLUE);
            insertDTO.getSource().remove("creatorId");
            paasEsModel.update(insertDTO);
        }
        if (Objects.nonNull(entity.getSubFormData()) && !entity.getSubFormData().isEmpty()) {
            entity.getData().putAll(entity.getSubFormData());
        }
        return success;
    }

    @Override
    public List<ClueEntityExt> findEntitys(Map<String, Object> param) {
        List<ClueEntityExt> entityExts = clueDao.findEntitys(param);
        Object corpid = param.get(ParameterConstant.CORPID);
        if (Objects.nonNull(corpid)) {
            paasFormSubDataModel.findSubEntity(corpid.toString(), entityExts, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        }
        return entityExts;
    }

    @Override
    public List<RuleClueEntity> getMainClueList4Rule(String corpid, List<Long> idIn) {
        return clueDao.getMainClueList4Rule(corpid, idIn);
    }

    @Override
    public List<RuleClueEntity> getMainClueListByUserId(String corpid, String userId, String statusStr, Integer pageNum, Integer pageSize, String orderField, List<Integer> sortList, List<Long> clueIdIn) throws XbbException {

        //当没有线索集合时
        if(clueIdIn != null && clueIdIn.size() == 0){
            return new ArrayList<>();
        }
        List<RuleClueEntity> clueList = getMainClueListByUserIdFromDb(corpid, userId, statusStr, pageNum, pageSize, orderField, sortList, clueIdIn);
        return clueList;
    }

    private List<RuleClueEntity> getMainClueListByUserIdFromDb(String corpid, String userId, String statusStr, Integer pageNum, Integer pageSize, String attr, List<Integer> sortList, List<Long> clueIdIn) throws XbbException {
        if (Objects.equals(pageSize, 0)) {
            return new ArrayList<>();
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        //解析查询条件
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery("flowStatus", FlowStatusEnum.getStatisticType()));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        if (Objects.nonNull(statusStr)) {
            boolQueryBuilder.filter(termQuery(ClueEnum.getAttrConnectData(ClueEnum.CLUE_STATUS), statusStr));
        }
        if (CollectionsUtil.isNotEmpty(clueIdIn)) {
            boolQueryBuilder.filter(termsQuery(StringConstant.DATA_ID, clueIdIn));
        }
        HasChildQueryBuilder hasChildQueryBuilder = esHelper.teamQueryBuilder(IndexTypeEnum.IDX_SAAS_CLUE_TEAM, corpid, BasicConstant.ONE, Arrays.asList(userId));
        boolQueryBuilder.filter(hasChildQueryBuilder);
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));
        sourceBuilder.query(boolQueryBuilder);
        List<String> fieldList = Arrays.asList(StringConstant.DATA_ID, "appId", "formId", "menuId", "corpid",
                ClueEnum.COMPANY_NAME.getAttr(), ClueEnum.LAST_CONNECT_TIME.getAttr(),
                ClueEnum.CLUE_STATUS.getAttr(), ClueEnum.LABEL.getAttr());
        EsUtil.setFieldList(sourceBuilder, fieldList);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CLUE.getIndex());
        if (Objects.isNull(pageNum) || Objects.equals(pageNum, 0)) {
            pageNum = 1;
        }
        if (Objects.isNull(pageSize)) {
            pageSize = EsNormalConstant.FIND_NUM;
        }
        if (StringUtil.isNotEmpty(attr) && CollectionsUtil.isNotEmpty(sortList)) {
            ScriptSortBuilder scriptSortBuilder = new ScriptSortBuilder(getScript(attr, sortList), ScriptSortBuilder.ScriptSortType.NUMBER);
            sourceBuilder.sort(scriptSortBuilder);
        } else {
            sourceBuilder.sort("dataId", SortOrder.ASC);
        }
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, pageNum, pageSize);
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ClueEntityExt> ClueEntityExtList = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ClueEntityExt.class);
        List<ClueEntityExt> clueEntityExts = ClueEntityExtList.getContent();
        return formatRuleClue(clueEntityExts);
    }

    private List<RuleClueEntity> formatRuleClue(List<ClueEntityExt> clueEntityExts) {
        List<RuleClueEntity> ruleCustomers = new ArrayList<>();
        for (ClueEntityExt clueEntity : clueEntityExts) {
            RuleClueEntity ruleClueEntity = new RuleClueEntity();
            ruleClueEntity.setId(clueEntity.getDataId());
            ruleClueEntity.setAppId(clueEntity.getAppId());
            ruleClueEntity.setFormId(clueEntity.getFormId());
            ruleClueEntity.setMenuId(clueEntity.getMenuId());
            ruleClueEntity.setCorpid(clueEntity.getCorpid());
            JSONObject data = clueEntity.getData();
            String name = data.getString(ClueEnum.COMPANY_NAME.getAttr());
            Integer type = data.getInteger(ClueEnum.CLUE_STATUS.getAttr());
            String labels = data.getString(ClueEnum.LABEL.getAttr());
            Long lastConnectTime = data.getLong(ClueEnum.LAST_CONNECT_TIME.getAttr());
            ruleClueEntity.setName(name);
            ruleClueEntity.setType(type);
            ruleClueEntity.setLabels(labels);
            ruleClueEntity.setLastConnectTime(lastConnectTime);
            ruleCustomers.add(ruleClueEntity);
        }
        return ruleCustomers;
    }

    /**
     * 获取排序脚本
     * @param attr
     * @param sortList
     * @return
     * @throws XbbException
     */
    private Script getScript(String attr, List<Integer> sortList) throws XbbException {
        if (StringUtil.isEmpty(attr) || CollectionsUtil.isEmpty(sortList)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100002, "排序参数错误！");
        }
        String scriptStr = null;
        if (Objects.equals(attr, ClueEnum.getAttrConnectData(ClueEnum.CLUE_STATUS))) {
            scriptStr = getStringScriptStr(attr);
        }
        return new Script(ScriptType.INLINE, "painless", scriptStr, getParams(sortList));
    }

    private Map<String, Object> getParams(List<Integer> sortList) {
        if (CollectionsUtil.isEmpty(sortList)) {
            return new HashMap<>();
        }
        //预设的排序值数量
        Integer sortNum = 30;
        //存排序字段的值，若排序字段值的数量不到30，则由大数据补齐，9999-(29-index)
        //values[0]:1, values[1]:10, values[2]:3, values[3]:9973, values[4]:9974, ... values[29]:9999
        List<Integer> values = new ArrayList<>();
        //排序权重值
        // 脚本中1被占用从2开始：sortValues[0]:2, sortValues[1]:3, sortValues[2]:4, ... sortValues[29]:31
        List<Integer> sortValues = new ArrayList<>();

        for(int i = 0; i < sortNum; i++){
            //先由需要排序字段的值填充
            if (i < sortList.size()) {
                values.add(sortList.get(i));
            } else {
                values.add( 9999-(29-i) );
            }
            sortValues.add( i + 2 );
        }
        Map<String, Object> params = new HashMap<>();
        params.put("values", values);
        params.put("sortValues", sortValues);
        return params;
    }

    /**
     * if(doc['data.text_4.raw'].size()==0){return 1;}
     * else if(Long.parseLong(doc['data.text_4.raw'].value)==params['values'][0]){return params['sortValues'][0];}
     * else if(Long.parseLong(doc['data.text_4.raw'].value)==params['values'][1]){return params['sortValues'][1];}
     * else if(Long.parseLong(doc['data.text_4.raw'].value)==params['values'][2]){return params['sortValues'][2];}
     * .
     * .
     * .
     * else if(Long.parseLong(doc['data.text_4.raw'].value)==params['values'][29]){return params['sortValues'][29];}
     * return Long.parseLong(doc['data.text_4.raw'].value)
     * @param attr
     * @return
     */
    private String getStringScriptStr(String attr) throws XbbException {
        StringBuffer sb = new StringBuffer();
        //空值处理，key不存在或为空字符串
        //if(doc['
        sb.append("if(doc['");
        //if(doc['data.text_4
        sb.append(attr);
        //if(doc['data.text_4.raw'].size()==0){return 1;}
        sb.append(".raw'].size()==0){return 1;}");
        for (Integer i = 0; i < 30; i++) {
            sb.append("else if(Long.parseLong(doc['");
            sb.append(attr);
            sb.append(".raw'].value)==params['values'][");
            sb.append(i);
            sb.append("]){return params['sortValues'][");
            sb.append(i);
            sb.append("];}");
        }
        sb.append("return Long.parseLong(doc['");
        sb.append(attr);
        sb.append(".raw'].value)");
        return sb.toString();
    }

    @Override
    public List<RuleClueEntity> getClueListByIdIn(String corpid, List<Long> clueIdIn) {
        return clueDao.getClueListByIdIn(corpid, clueIdIn);
    }

    @Override
    public Integer getMainClueCountByUserId(String corpid, String userId) {
        Integer count = clueDao.getClueCount4MaxClueNum(corpid, userId, null, null);
        return count;
    }

    @Override
    public Integer getMainClueCountByUserId(String corpid, String userId, String statusStr) {
        Integer count = clueDao.getClueCount4MaxClueNum(corpid, userId, null, statusStr);

        return count;
    }



    /**
     * 按手机号查询线索
     *
     * @param corpid 公司ID
     * @param phone  用于判重的手机号
     * @return CustomerEntityExt
     * @author youli.chen
     * @date 2019/1/23 20:27
     * @since v1.0
     */
    @Override
    public ClueEntityExt getByPhone(String corpid, String phone) throws XbbException {
        if (StringUtil.isEmpty(phone)) {
            return null;
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        //解析查询条件
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        // 电话拨打，采用精确查询
        boolQueryBuilder.filter(termQuery("data."+ ClueEnum.PHONE.getAttr() + "." + StringConstant.PHONE_TEL_ATTR + ".keyword", phone));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CLUE.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ClueEntityExt> clueEntityExtList = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ClueEntityExt.class);
        if (clueEntityExtList.getContent().size() == 0) {
            return null;
        } else {
            ClueEntityExt clueEntityExt = clueEntityExtList.getContent().get(0);
            paasFormSubDataModel.findSubEntity(corpid, Collections.singletonList(clueEntityExt), IndexTypeEnum.IDX_SAAS_CLUE_SUB);
            return clueEntityExt;
        }
    }

    @Override
    public ClueEntityExt getByPhoneIncloudRecycled(String corpid, String phone) throws XbbException {
        if (StringUtil.isEmpty(phone)) {
            return null;
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        //解析查询条件
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
//        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery("del", Arrays.asList(DelEnum.NORMAL.getDel(), DelEnum.DELETE.getDel())));
        // 电话拨打，采用精确查询
        boolQueryBuilder.filter(termQuery("data."+ ClueEnum.PHONE.getAttr() + "." + StringConstant.PHONE_TEL_ATTR + ".keyword", phone));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CLUE.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ClueEntityExt> clueEntityExtList = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ClueEntityExt.class);
        if (clueEntityExtList.getContent().size() == 0) {
            return null;
        } else {
            ClueEntityExt clueEntityExt = clueEntityExtList.getContent().get(0);
            paasFormSubDataModel.findSubEntity(corpid, Collections.singletonList(clueEntityExt), IndexTypeEnum.IDX_SAAS_CLUE_SUB);
            return clueEntityExt;
        }
    }

    @Override
    public List<ClueEntityExt> listByInPhone(String corpid, List<String> phoneList,boolean dontQueryDel) throws XbbException {
        if (CollectionUtils.isEmpty(phoneList)) {
            return new ArrayList<>();
        }
        Set<String> phoneSet = phoneList.stream().filter(StringUtil::isNotEmpty).collect(Collectors.toSet());
        if (CollectionsUtil.isEmpty(phoneSet)) {
            return new ArrayList<>();
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        //解析查询条件
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        if (!dontQueryDel) {
            boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        } else {
            List<Integer> delList = new ArrayList<>(2);
            delList.add(DelEnum.NORMAL.getDel());
            delList.add(DelEnum.DELETE.getDel());
            boolQueryBuilder.filter(QueryBuilders.termsQuery("del", delList));
        }
        // 电话拨打，采用精确查询
        boolQueryBuilder.filter(QueryBuilders.termsQuery("data."+ ClueEnum.PHONE.getAttr() + "." + StringConstant.PHONE_TEL_ATTR + ".keyword", phoneSet));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CLUE.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 500);
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ClueEntityExt> clueEntityExtList = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ClueEntityExt.class);
        List<ClueEntityExt> content = clueEntityExtList.getContent();
        if (CollectionUtils.isEmpty(content)) {
            return new ArrayList<>();
        }
        paasFormSubDataModel.findSubEntity(corpid, content, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        return content;
    }


    @Override
    public Integer getEntitysCount(Map<String, Object> param) {
        return clueDao.getEntitysCount(param);
    }

    @Override
    public List findEntitysWithoutSub(Map<String, Object> param) {
        return clueDao.findEntitys(param);
    }

    @Override
    public void jsonsetNoSubById(String corpid, Long id, Map<String, Object> map) throws XbbException{
        StandardizeDataUtil.standardizeMap(map);
        Map<String,Object> map2 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,Object> updateDataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        JSONObject jsonObject = new JSONObject();
        Long now = DateTimeUtil.getInt();
        for (Map.Entry<String,Object> entry : map.entrySet()){
            String key = entry.getKey();
            map2.put("$."+key,entry.getValue());
            jsonObject.put(key,entry.getValue());
        }
        updateDataMap.put("data", jsonObject);
        clueDao.jsonSetAndUpdateTime(corpid, id, map2, now);
        InsertDTO insertDTO = new InsertDTO();
        updateDataMap.put(FieldTypeEnum.UPDATETIME.getAlias(), now);
        insertDTO.setSource(updateDataMap);
        insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CLUE);
        insertDTO.setEsId(corpid+"_"+id);
        paasEsModel.update(insertDTO);
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.CLUE, operateTypeEnum = OperateTypeEnum.DELETE, isBatch = true)
    public Integer deleteBatch(List<Long> idIn, String corpid) throws XbbException {
        Integer integer = clueDao.deleteBatch(idIn, corpid);
        paasEsModel.deleteBatch(idIn, corpid, DelEnum.DELETE.getDel(), IndexTypeEnum.IDX_SAAS_CLUE);
        paasFormSubDataModel.deleteBatchByDataId(idIn, corpid, IndexTypeEnum.IDX_SAAS_CLUE_SUB, DelEnum.DELETE_SUBFORM);
        return integer;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.CLUE, operateTypeEnum = OperateTypeEnum.DELETE)
    public Integer deleteByKey(Long key,String corpid) throws XbbException{
        DeleteDTO deleteDTO = new DeleteDTO();
        deleteDTO.setEsId(corpid+"_"+key);
        deleteDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CLUE);
        paasEsModel.delete(deleteDTO);
        paasFormSubDataModel.deleteByDataId(key,corpid,IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        return clueDao.deleteByKey(key,corpid);
    }

    @Override
    public Integer restoreBatch(List<Long> dataIdList, String corpid, Integer del, String publicAttr) throws XbbException{
        String dataStr = "$." + publicAttr;
        Integer count = clueDao.restoreBatch(dataIdList, corpid, del, dataStr);
        updateBatchDel(dataIdList, corpid, del, publicAttr);

        paasFormSubDataModel.restoreBatch(dataIdList, corpid, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        return count;
    }

    @Override
    public Integer thoroughDeleteBatch(List<Long> dataIdList, String corpid, Integer del) throws XbbException {
        Integer count = clueDao.thoroughDeleteBatch(dataIdList, corpid, del);
        updateBatchDel(dataIdList, corpid, del, null);
        List<? extends PaasFormSubDataEntity> entities = paasFormSubDataModel.getByDataIdList(dataIdList, DelEnum.DELETE_SUBFORM.getDel(), corpid, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        clueSubDataModel.updateDel((List<ClueSubDataEntity>)  entities,corpid,  WriteRequest.RefreshPolicy.NONE, DelEnum.getByDel(del));
        return count;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.CLUE, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer updateBatch(List<UpdateDataEntity> updateDataList, String corpid) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(updateDataList);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(updateDataList);
        Integer integer = 0;
        if (CollectionsUtil.isNotEmpty(updateDataList)) {
            StandardizeDataUtil.standardizeList(updateDataList);
            integer = clueDao.batchUpdate(updateDataList, corpid);
            paasEsModel.updateBatchMuchField(updateDataList, IndexTypeEnum.IDX_SAAS_CLUE);
        }
        if (!subList.isEmpty()) {
            clueSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.CLUE, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer updateBatch(List<UpdateDataEntity> updateDataList, String corpid,WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(updateDataList);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(updateDataList);
        Integer integer = 0;
        if (CollectionsUtil.isNotEmpty(updateDataList)) {
            StandardizeDataUtil.standardizeList(updateDataList);
            integer = clueDao.batchUpdate(updateDataList, corpid);
            paasEsModel.updateBatchMuchField(updateDataList, IndexTypeEnum.IDX_SAAS_CLUE, refreshPolicy);
        }
        if (!subList.isEmpty()) {
            clueSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    public List<ClueEntityExt> getByKeys(List<Long> keys, String corpid) {

        Map<String, Object> param = new HashMap<>();
        param.put("corpid", corpid);
        param.put("ids", keys);
        param.put("del", BasicConstant.ZERO);

        return findEntitys(param);
    }

    @Override
    public void updateBatchNoSub(String corpid, List<Long> dataIdList, Map<String, Object> map, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        StandardizeDataUtil.standardizeMap(map);
        Map<String,Object> map2 = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String,Object> updateDataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        JSONObject jsonObject = new JSONObject();
        for (Map.Entry<String,Object> entry : map.entrySet()){
            String key = entry.getKey();
            map2.put("$."+key,entry.getValue());
            jsonObject.put(key,entry.getValue());
        }
        updateDataMap.put("data", jsonObject);
        clueDao.updateBatch(corpid, dataIdList, map2);
        List<InsertDTO> insertList = new ArrayList<>();
        for (Long id : dataIdList) {
            InsertDTO insertDTO = new InsertDTO();
            insertDTO.setSource(updateDataMap);
            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CLUE);
            insertDTO.setEsId(corpid+"_"+id);
            insertList.add(insertDTO);
        }
        if(refreshPolicy != null){
            paasEsModel.updateBatch(insertList, refreshPolicy);
        }else{
            paasEsModel.updateBatch(insertList);
        }
    }

    private void updateBatchDel(List<Long> dataIdList, String corpid, Integer del, String publicStr) throws XbbException{
        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (StringUtil.isNotEmpty(publicStr)) {
            JSONObject obj = new JSONObject();
            obj.put(publicStr, 1);
            map.put(StringConstant.JSON_DATA, obj);
        }
        map.put("del", del);
        map.put("updateTime",DateTimeUtil.getInt());
        paasFormDataEsModel.updateBatch(dataIdList, corpid, map,IndexTypeEnum.IDX_SAAS_CLUE);
    }

    @Override
    public void formatUpdateExplain(FormatExplainDTO formatExplainDTO) throws XbbException {
        List<FieldAttrEntity> explainList = formatExplainDTO.getExplainList();
        Integer isPublic = getIntegerOrDefaultFromFormData(formatExplainDTO.getResult(), ClueEnum.IS_PUBLIC.getAttr(), 0);
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            String attr = fieldAttrEntity.getAttr();
            if (Objects.equals(attr, ClueEnum.CLUE_STAGE.getAttr()) && (Objects.isNull(formatExplainDTO.getFromCopy()) || !formatExplainDTO.getFromCopy())) {
                fieldAttrEntity.setEditable(0);
                fieldAttrEntity.setMemo(I18nMessageUtil.getMessage(I18nStringConstant.FILL_IN_FEEDBACK_MEMO));
            }
            if (Objects.equals(isPublic, 1) && (Objects.isNull(formatExplainDTO.getFromCopy()) || !formatExplainDTO.getFromCopy())) {
                // 复制不走这里
                if (Objects.equals(attr, ClueEnum.OWNER_ID.getAttr())) {
                    DefaultAttrPoJo defaultAttrPoJo = new DefaultAttrPoJo();
                    defaultAttrPoJo.setDefaultType(null);
                    defaultAttrPoJo.setDefaultValue("");
                    fieldAttrEntity.setDefaultAttr(defaultAttrPoJo);
                    fieldAttrEntity.setEditable(0);
                } else if (Objects.equals(attr, ClueEnum.COUSERID.getAttr())) {
                    fieldAttrEntity.setEditable(0);
                }
            }
        }
    }

    @Override
    public void formatData(SaasAnalysisDataDTO formDataUpdateGetDTO, JSONObject result) throws XbbException {
        showFormatHelp.formatLinkBusiness4Show(result, ClueEnum.MARKET_ACTIVITY_ID.getAttr(), ClueEnum.MARKET_ACTIVITY_NAME.getAttr(), ClueEnum.MARKET_ACTIVITY_ID.getFieldType());
    }
    @Override
    public Integer updateTime(Long id,String corpid) throws XbbException {
        long now = DateUtil.getInt();
        // 更新时间
        Integer success = clueDao.updateTime(now, id, corpid);
        // 更新es
        PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
        paasFormDataEntity.setId(id);
        paasFormDataEntity.setDataId(id);
        paasFormDataEntity.setCorpid(corpid);
        paasFormDataEntity.setUpdateTime(now);
        InsertDTO insertDTO = paasEsModel.getSaveDTO(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_CLUE);
        paasEsModel.update(insertDTO);
        return success;
    }

    @Override
    public void insertBatch(List<PaasFormDataEntity> paasFormDataEntityList) throws XbbException {
        for (PaasFormDataEntity paasFormDataEntity : paasFormDataEntityList) {
            paasFormSubDataModel.transferSubForm(paasFormDataEntity, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
        }
        StandardizeDataUtil.standardize4EntityList(paasFormDataEntityList);
        clueDao.insertBatch(paasFormDataEntityList);
        //ES数据插入
        List<InsertDTO> insertList = new ArrayList<>();
        for (PaasFormDataEntity item : paasFormDataEntityList) {
            InsertDTO insertDTO = new InsertDTO();
            insertDTO.setEsId(item.getCorpid() + "_" + item.getId());
            item.setDataId(item.getId());
            insertDTO.setSource(BeanUtil.convertBean2Map(item, true));
            insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_SAAS_CLUE);
            insertList.add(insertDTO);
        }
        paasEsModel.insertBatch(insertList);

        paasFormSubDataModel.insertBatchSubFormData(paasFormDataEntityList, IndexTypeEnum.IDX_SAAS_CLUE_SUB);
    }

    @Override
    public List<FineClueScriptEntity> getListByPids(String corpid, List<String> pids) {
        return clueDao.getClueListByFineCluePids(corpid, pids);
    }
}
